/*
 * $Id: string_strspl.c,v 1.3 2005-07-01 05:07:24 bacon Exp $
 */

#if defined(__MSTRING)
#include <xp/bas/mstring.h>
#elif defined(__WSTRING)
#include <xp/bas/wstring.h>
#else
#include <xp/bas/string.h>
#endif
#include <xp/bas/ctype.h>

int xp_strspl (xp_char_t* s, const xp_char_t* delim, 
	xp_char_t lquote, xp_char_t rquote, xp_char_t escape, xp_size_t* count)
{
	xp_char_t* p = s, *d;
	xp_char_t* sp = XP_NULL, * ep = XP_NULL;
	int delim_mode;
	xp_size_t cnt = 0;

	if (delim == XP_NULL) delim_mode = 0;
	else {
		delim_mode = 1;
		for (d = (xp_char_t*)delim; *d != XP_CHAR('\0'); d++) 
			if (!xp_isspace(*d)) delim_mode = 2;
	}

	if (delim_mode == 0) { 
		/* skip preceding space characters */
		while (xp_isspace(*p)) p++;

		/* when 0 is given as "delim", it has an effect of cutting
		   preceding and trailing space characters off "s". */
		if (lquote != XP_CHAR('\0') && *p == lquote) {
			xp_strcpy (p, p + 1);

			for (;;) {
				if (*p == XP_CHAR('\0')) return -1;

				if (escape != XP_CHAR('\0') && *p == escape) {
					xp_strcpy (p, p + 1);
				}
				else {
					if (*p == rquote) {
						p++;
						break;
					}
				}

				if (sp == 0) sp = p;
				ep = p;
				p++;
			}
			while (xp_isspace(*p)) p++;
			if (*p != XP_CHAR('\0')) return -1;

			if (sp == 0 && ep == 0) s[0] = XP_CHAR('\0');
			else {
				ep[1] = XP_CHAR('\0');
				if (s != (xp_char_t*)sp) xp_strcpy (s, sp);
				cnt++;
			}
		}
		else {
			while (*p) {
				if (!xp_isspace(*p)) {
					if (sp == 0) sp = p;
					ep = p;
				}
				p++;
			}

			if (sp == 0 && ep == 0) s[0] = XP_CHAR('\0');
			else {
				ep[1] = XP_CHAR('\0');
				if (s != (xp_char_t*)sp) xp_strcpy (s, sp);
				cnt++;
			}
		}
	}
	else if (delim_mode == 1) {
		xp_char_t* o;

		while (*p) {
			o = p;
			while (xp_isspace(*p)) p++;
			if (o != p) { xp_strcpy (o, p); p = o; }

			if (lquote != XP_CHAR('\0') && *p == lquote) {
				xp_strcpy (p, p + 1);

				for (;;) {
					if (*p == XP_CHAR('\0')) return -1;

					if (escape != XP_CHAR('\0') && *p == escape) {
						xp_strcpy (p, p + 1);
					}
					else {
						if (*p == rquote) {
							*p++ = XP_CHAR('\0');
							cnt++;
							break;
						}
					}
					p++;
				}
			}
			else {
				o = p;
				for (;;) {
					if (*p == XP_CHAR('\0')) {
						if (o != p) cnt++;
						break;
					}
					if (xp_isspace (*p)) {
						*p++ = XP_CHAR('\0');
						cnt++;
						break;
					}
					p++;
				}
			}
		}
	}
	else { /* if (delim_mode == 2) { */
		xp_char_t* o;
		int ok;

		while (*p) {
			o = p;
			while (xp_isspace(*p)) p++;
			if (o != p) { xp_strcpy (o, p); p = o; }

			if (lquote != XP_CHAR('\0') && *p == lquote) {
				xp_strcpy (p, p + 1);

				for (;;) {
					if (*p == XP_CHAR('\0')) return -1;

					if (escape != XP_CHAR('\0') && *p == escape) {
						xp_strcpy (p, p + 1);
					}
					else {
						if (*p == rquote) {
							*p++ = XP_CHAR('\0');
							cnt++;
							break;
						}
					}
					p++;
				}

				ok = 0;
				while (xp_isspace(*p)) p++;
				if (*p == XP_CHAR('\0')) ok = 1;
				for (d = (xp_char_t*)delim; *d != XP_CHAR('\0'); d++) {
					if (*p == *d) { 
						ok = 1; 
						xp_strcpy (p, p + 1);
						break; 
					}
				}
				if (ok == 0) return -1;
			}
			else {
				o = p; sp = ep = 0;

				for (;;) {
					if (*p == XP_CHAR('\0')) {
						if (ep) {
							ep[1] = XP_CHAR('\0');
							p = &ep[1];
						}
						cnt++;
						break;
					}
					for (d = (xp_char_t*)delim; *d != XP_CHAR('\0'); d++) {
						if (*p == *d)  {
							if (sp == XP_NULL) {
								xp_strcpy (o, p); p = o;
								*p++ = XP_CHAR('\0');
							}
							else {
								xp_strcpy (&ep[1], p); 
								xp_strcpy (o, sp);
								o[ep - sp + 1] = XP_CHAR('\0');
								p = &o[ep - sp + 2];
							}
							cnt++;
							/* last empty field after delim */
							if (*p == XP_CHAR('\0')) cnt++; 
							goto exit_point;
						}
					}

					if (!xp_isspace (*p)) {
						if (sp == XP_NULL) sp = p;
						ep = p;
					}
					p++;
				}
exit_point:				
				;
			}
		}
	}

	*count = cnt;
	return 0;
}

int xp_strspls (
	xp_char_t* s, const xp_char_t* delim, xp_char_t lquote, xp_char_t rquote, 
	xp_char_t escape, xp_size_t* count, xp_char_t* ptrs[])
{
	xp_size_t cnt = *count, i;

	if (xp_strspl (s, delim, lquote, rquote, escape, count) == -1) return -1;
	for (i = 0; i < *count && i < cnt; i++) {
		ptrs[i] = s;
		s += xp_strlen(s) + 1;
	}
	return 0;
}
